<?php

/**
 * @copyright ©2022 QuickAdmin
 * @author QinTingWei
 * @link http://www.quickadmin.cn/
 * Date Time: 2023/10/26
 */

namespace quick\admin\http\model;


use quick\admin\library\queue\job\HandleServiceJob;
use quick\admin\library\tools\CsvExport;
use quick\admin\table\Column;
use quick\admin\table\Table;
use think\db\Query;
use think\facade\Log;
use think\queue\Job;

abstract class CommonExport
{

    public $fieldsKeyList;


    public $fieldsNameList;


    public $dirName = 'test';


    private $job;


    /**
     * 禁止分页
     * @var bool
     */
    public $disPage = true;


    /**
     * 数据源
     * @var
     */
    public $dataList;


    private $exportFields = [];

    /**
     * @var array
     */
    private $extraFields = [];


    /**
     * @return array
     */
    public function getExtraFields(): array
    {
        return $this->extraFields;
    }


    /**
     * @param array $extraFields
     */
    public function setExtraFields(array $extraFields)
    {
        $this->extraFields = $extraFields;
        return $this;
    }

    private $exportIds = [];

    private $key = 'id';

    /**
     * @var
     */
    public $query;

    abstract public function fieldsList();


    /**
     * @param $query
     * @return mixed
     */
    abstract public function export($query);

    /**
     * 数据转换
     * @param $list
     * @return mixed
     */
    abstract protected function transform(array $list);


    public function getSelectFields()
    {
        $fields = $this->fieldsList();
        $keyValue = [];
        $fields = array_merge($fields,$this->getExtraFields());


        foreach ($fields as $k => $v){
            $keyValue[] = [
                'key' => $k,
                'value' => $v,
            ];
        }
        return $keyValue;
    }


    /**
     * 可导出字段
     * @param array $fields
     * 空导出全部 ['字段名称1','字段名称2','字段名称3']
     * @return $this
     */
    public function setFields(array $fields)
    {
        $this->exportFields = $fields;
        return $this;
    }


    /**
     * 可导出数据
     * @param array $fields
     * 空导出全部 ['id1','id2','id3']
     * @return $this
     */
    public function setExportIds(array $ids)
    {
        $this->exportIds = $ids;
        return $this;
    }

    /**
     * @return array
     */
    public function getExportFields():array
    {

        $fields = $this->getSelectFields();
        $newFields = [];
        foreach ($fields as  $item){
            if(empty($this->exportFields) || in_array($item['key'],$this->exportFields)){
                $newFields[$item['key']] = $item['value'];
            }
        }
        return $newFields;

    }

    public function getFieldName(string $name = '数据列表'): string
    {
        return $name.date('YmdHi');
    }


    /**
     * @param $data
     * @return $this
     */
    public function setDataList($data)
    {
        $this->dataList = $data;
        return $this;
    }


    /**
     * 导出数据到文件
     * @param array $data
     * @param array $headerArr
     * @return string|void
     */
    public function handleExport(array $data,array $headerArr){
        $csv  = new CsvExport();
        $time = time();
        $name = 'test-'.$time.'.csv';
        return $csv->asyncExport($data,$headerArr,$name,$this->dirName);
    }


    public function handle(Job $job)
    {
        $this->job = $job;
        /** Job $job */
        $this->progress(2,"---开始导出--");
        return $this->exportAction();
    }


    /**
     * @param int|null $status
     * 任务状态  2.进行中 3.完成 4.失败
     * @param string|null $message
     * @param string|null $progress
     * @param int $backline
     */
    public function progress(?int $status = null, ?string $message = null, ?string $progress = null, int $backline = 0)
    {
        if($this->job instanceof Job){
            $this->job->progress($status,$message,$progress,$backline,"---开始导出--");
        }else{
            Log::info("导入日志---:".$message);
        }
    }

    public function queueAction()
    {
        $queueService = new HandleServiceJob();
        $queueService->setService($this);
        $queueId = $queueService->queue();
        return $queueId;
    }

    /**
     * 执行导出
     */
    public function exportAction()
    {

        $filePath = null;
        Log::warning('---------导出开始 ------>');
        try {


            $headerList = $this->getExportFields();

            $dataList = $this->buildExportData($this->dataList,$headerList);

            $filePath = $this->handleExport($dataList,$headerList);
            Log::warning('------导出结束---->'.$filePath);
            $this->progress(3,"---导出完成--");
        }catch(\Exception $exception) {
             Log::error('导出异常'.$exception->getLine());
             Log::error($exception->getMessage());
            $this->progress(4,$exception->getMessage());
             return false;

        }catch(\Error $exception) {
             Log::error('导出异常'.$exception->getLine());
             Log::error($exception->getMessage());
            $this->progress(4,$exception->getMessage());
            return false;
        }

        return $filePath;
    }



    protected function getTableData(array $list,&$headerList)
    {
        $newData = [];
        foreach ($list as $item){
            $headerArr = [];
            $row = [];
            $oriRow = [];
            /** @var Column $vo */
            foreach ($item as $key => $vo){

                if(in_array($key,['_key','_actions'])){

                    continue;
                }

                if($key == '_children'){
                    $data = $this->getTableData($vo,$headerList);
                    $newData = array_merge($newData , $data);
                    continue;
                }

                $headerArr[$vo->name] = $vo->getTitle();
                $d = $vo->jsonSerialize();

                $oriRow = $vo->getRowData();
                if(empty($oriRow)){
                    $oriRow = [];
                }
                $row[$this->key] = $oriRow[$this->key];

                if(empty($headerList) || isset($headerList[$vo->name]) ){
                    $row[$vo->name] = $d['value'];
                }

            }

            foreach ($headerList as $hk => $hvo){
                if(isset($oriRow[$hk]) &&
                    !isset($row[$hk])){
                    $row[$hk] = $oriRow[$hk];
                }
            }

            if($this->dataRowCan($row[$this->key])){
                $row = $this->transform($row);
                $newData[] = $row;
            }

            if(empty($headerList)){
                $headerList = $headerArr;
            }
        }



        return $newData;

    }


    protected function buildExportData($dataList,array &$headerList)
    {

        $newData = [];
        if($dataList instanceof Query){
            $dataList = $dataList->select()->toArray();
        }
        if($dataList instanceof \quick\admin\table\Query){
            $dataList = $dataList->getThinkModel()->select()->toArray();
        }


        foreach ($dataList as $item){
            $newRow = [];
            foreach ($headerList as $hk => $hvo){
                $value = data_get($item, $hk);
                $newRow[$hk] = $value;
            }
            if($this->dataRowCan($newRow[$this->key])){
                $newRow = $this->transform($newRow);
                $newData[] = $newRow;
            }

        }
        return $newData;
    }



    private function dataRowCan($key)
    {
        if(empty($this->exportIds) || in_array($key, $this->exportIds)){
            return true;
        }
        return false;
    }


}